/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package commandline;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Semaphore;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author thinner
 */
public class CommandLineMethods {

    private Logger logger;

    public CommandLineMethods() {
        this(Logger.getLogger(CommandLineMethods.class.getName()));
    }

    public CommandLineMethods(Logger logger) {
        this.logger = logger;
    }

    public Process exec(String cmd) throws IOException {
        return exec(cmd, null);
    }

    public Process exec(String cmd, File workingDirectory) throws IOException {
        System.out.println("Executing: >" + cmd + "< in >"
                + ((workingDirectory == null)
                ? new File(".").getAbsolutePath()
                : workingDirectory.getAbsolutePath()) + "<");
        return Runtime.getRuntime().exec(cmd, null, workingDirectory);
    }

    public String readProcess(Process p) {
        final InputStream stdin = p.getInputStream();
        final InputStream stderr = p.getErrorStream();

        final Semaphore notify = new Semaphore(0, true);
        final ThreadBoolean errorOccured = new ThreadBoolean(false);
        final StringBuffer error = new StringBuffer();
        final StringBuffer input = new StringBuffer();

        Thread errorThread = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    int c;
                    while ((c = stderr.read()) != -1) {
                        errorOccured.b = true;
                        error.append((char) c);
                    }
                    notify.release();
                } catch (IOException ex) {
                    logger.log(Level.SEVERE, null, ex);
                }
            }
        });
        errorThread.start();

        Thread stdinThread = new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                    int c;
                    while ((c = stdin.read()) != -1) {
                        input.append((char) c);
                        if (errorOccured.b) {
                            return;
                        }
                    }
                    notify.release();
                } catch (IOException ex) {
                    logger.log(Level.SEVERE, null, ex);
                }
            }
        });
        stdinThread.start();

        notify.acquireUninterruptibly(2);
        if (errorOccured.b) {
            stdinThread.interrupt();
            return error.toString();
        } else {
            errorThread.interrupt();
            return input.toString();
        }
    }

    public void listenToProcess(Process p, ProcessListener listener) {
        InputStream stdin = p.getInputStream();
        InputStream stderr = p.getErrorStream();

        Thread errorThread = new ThreadProcess(listener, stderr);
        errorThread.start();

        Thread stdinThread = new ThreadProcess(listener, stdin);
        stdinThread.start();
    }

    private class ThreadBoolean {

        public boolean b;

        public ThreadBoolean(boolean b) {
            this.b = b;
        }
    }

    private class ThreadProcess extends Thread {

        private ProcessListener listener;
        private InputStream stream;

        public ThreadProcess(ProcessListener listener, InputStream stream) {
            this.listener = listener;
            this.stream = stream;
        }

        @Override
        public void run() {
            try {
                byte[] b = new byte[128];
                while (stream.read(b) != -1) {
                    listener.newData(b);
                }
                listener.finished();
            } catch (IOException ex) {
                logger.log(Level.SEVERE, null, ex);
            }
        }
    }
}
